﻿using Credera.Theta.API;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Credera.Theta.Extensions;
using Credera.Theta.Component;

namespace Credera.Theta.Processing
{
    class CommandValidator
    {
        public InputCommand Command { get; set; }
        public HostContext HostContext { get; set; }
        public List<CommandValidatorError> Errors { get; set; }

        public IHostInterface Host { get; private set; }

        public CommandValidator(InputCommand command, HostContext hostContext)
        {
            this.Command = command;
            this.HostContext = hostContext;
            this.Errors = new List<CommandValidatorError>();

            this.EvaluateParameterAnalysis();
            this.ValidateParameterValues();
        }

        private void ValidateParameterValues()
        {
            var definition = this.Command.GetType().DescribeInputCommand();

            foreach (var param in definition.Parameters.Where(p => !string.IsNullOrWhiteSpace(p.ValidationValuesFunction)))
            {
                // get parameter value

                string value = (string)param.PropertyInfo.GetValue(this.Command);

                if (value != null) // compare to validation values
                {
                    // get validation values

                    var context = new ValidationValuesFunctionContext(this.HostContext);
                    var methodInfo = this.Command.GetType().GetMethod(param.ValidationValuesFunction);

                    try
                    {
                        methodInfo.Invoke(this.Command, new object[] { context });

                        // compare

                        if (!context.Values.Contains(value, StringComparer.OrdinalIgnoreCase))
                            this.Errors.Add(new CommandValidatorError()
                            {
                                Type = CommandValidationType.InvalidParameterValue,
                                Parameters = new List<ParameterDef>() { param },
                                Message = string.Format("The value of parameter {0} is invalid", param.Name)
                            });
                    }
                    catch (Exception ex)
                    {
                        this.Errors.Add(new CommandValidatorError()
                        {
                            Type = CommandValidationType.InvalidValidationValuesFunction,
                            Parameters = new List<ParameterDef>() { param },
                            Message = string.Format("An error occured during the invocation of the validation values function for parameter {0}", param.Name),
                            Error = ex
                        });
                    }
                }
            }
        }

        private void EvaluateParameterAnalysis()
        {
            CommandParameterAnalysis analysis = new CommandParameterAnalysis(this.Command);

            if (analysis.MissingRequiredParameters.Count() > 0)
                this.Errors.Add(new CommandValidatorError()
                {
                    Type = CommandValidationType.MissingRequiredParameters,
                    Parameters = analysis.MissingRequiredParameters,
                    Message = string.Format("Required parameters are missing [{0}]"
                        , string.Join(", ", analysis.MissingRequiredParameters.Select(p => p.Name).ToArray()))
                });

            if (analysis.SuperflousParameters.Count() > 0)
                this.Errors.Add(new CommandValidatorError()
                {
                    Type = CommandValidationType.SuperflousParametersPresent,
                    Parameters = analysis.SuperflousParameters,
                    Message = string.Format("Parameters not found in active set are present [{0}]"
                    , string.Join(", ", analysis.SuperflousParameters.Select(p => p.Name).ToArray()))
                });
        }
    }
}
